﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Core.Objects;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Newtonsoft.Json;
namespace BaseLib.Helper
{
    public static class Exts
    {
        #region - 获取分页数据 -
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entities"></param>
        /// <param name="pageIndex">要获取页</param>
        /// <param name="pageSize">页容量</param>
        /// <returns></returns>
        public static PagerList<TEntity> ToPagerList<TEntity>(this IQueryable<TEntity> entities, int pageIndex, int pageSize) where TEntity : class
        {
            return new PagerList<TEntity>
            {
                TotalCount = entities.Count(),
                Entities = entities.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()
            };
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entities"></param>
        /// <param name="pageIndex">要获取页</param>
        /// <param name="pageSize">页容量</param>
        /// <returns></returns>
        public static PagerList<TEntity> ToPagerList<TEntity>(this IEnumerable<TEntity> entities, int pageIndex, int pageSize) where TEntity : class
        {
            var list = entities.ToList();
            return new PagerList<TEntity>
            {
                TotalCount = list.Count(),
                Entities = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList()
            };
        }
        #endregion
        #region 生成匿名的List
        /// <summary>
        /// 生成匿名的List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public static List<T> MakeList<T>(this T t, params T[] items)
        {
            return new List<T>(items);
        }
        #endregion
        #region IQueryable扩展
        #region 返回集合中满足条件的元素列表
        /// <summary>
        /// 返回集合中满足条件的元素列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IQueryable<T> Query<T>(this  IQueryable<T> query, Expression<Func<T, bool>> predicate) where T : class
        {
            return query.Where<T>(predicate);
        }
        #endregion
        #region 返回集合中满足条件的第一个元素，如果未找到，则返回默认值
        /// <summary>
        /// 返回集合中满足条件的第一个元素，如果未找到，则返回默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T QueryByFirstOrDefault<T>(this  IQueryable<T> query, Expression<Func<T, bool>> predicate) where T : class
        {
            return query.FirstOrDefault(predicate);
        }
        #endregion
        #region 判断指定的列表中是否含有指定条件的元素
        /// <summary>
        /// 判断指定的列表中是否含有指定条件的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static bool IsExist<T>(this  IQueryable<T> query, Expression<Func<T, bool>> predicate) where T : class
        {
            return query.Any(predicate);
        }
        #endregion
        #endregion
        #region IEnumerable 扩展
        #region 返回集合中满足条件的元素列表
        /// <summary>
        /// 返回集合中满足条件的元素列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IEnumerable<T> Query<T>(this  IEnumerable<T> query, Func<T, bool> func)
        {
            return query.Where<T>(func);
        }
        #endregion
        #region 返回集合中满足条件的第一个元素，如果未找到，则返回默认值
        /// <summary>
        /// 返回集合中满足条件的第一个元素，如果未找到，则返回默认值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T QueryByFirstOrDefault<T>(this  IEnumerable<T> query, Func<T, bool> func)
        {
            return query.FirstOrDefault(func);
        }
        #endregion
        #region 判断指定的列表中是否含有指定条件的元素
        /// <summary>
        /// 判断指定的列表中是否含有指定条件的元素
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static bool IsExist<T>(this  IEnumerable<T> query, Func<T, bool> func)
        {
            return query.Any(func);
        }
        #endregion
        #endregion
        #region 中文处理
        public static List<int> PaseIntList(this string source, string separator)
        {
            var list = new List<int>();
            source.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries).ToList().ForEach(n => list.Add(n.ToInt(-1)));
            return list;
        }
        public static bool IsNotNullOrZero(this int? intNull)
        {
            return intNull.HasValue && intNull.Value != 0;
        }
        public static bool IsNullOrZero(this int? intNull)
        {
            return !intNull.HasValue || intNull.Value == 0;
        }
        #region 转全角(SBC case)
        /// <summary>
        /// 转全角(SBC case)
        /// </summary>
        /// <param name="input">任意字符串</param>
        /// <returns>全角字符串</returns>
        public static string ToSbc(this string input)
        {
            char[] chars = input.ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                if (chars[i] == 32)
                {
                    chars[i] = (char)12288;
                    continue;
                }
                if (chars[i] < 127)
                    chars[i] = (char)(chars[i] + 65248);
            }
            return new string(chars);
        }
        #endregion
        #region 转半角(DBC case)
        /// <summary>
        /// 转半角(DBC case)
        /// </summary>
        /// <param name="input">任意字符串</param>
        /// <returns>半角字符串</returns>
        public static string ToDbc(this string input)
        {
            char[] chars = input.ToCharArray();
            for (var i = 0; i < chars.Length; i++)
            {
                if (chars[i] == 12288)
                {
                    chars[i] = (char)32;
                    continue;
                }
                if (chars[i] > 65280 && chars[i] < 65375)
                {
                    chars[i] = (char)(chars[i] - 65248);
                }
            }
            return new string(chars);
        }
        #endregion
        #region 指示指定的字符串是 null 还是 System.String.Empty 字符串。
        /// <summary>
        /// 指示指定的字符串是 null 还是 System.String.Empty 字符串。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns>如果 value 参数为 null 或 System.String.Empty，或者如果 value 仅由空白字符组成，则为 true</returns>
        public static bool IsNullOrEmpty(this string s)
        {
            return string.IsNullOrEmpty(s);
        }
        #endregion
        #region 指示指定的字符串是 null、空还是仅由空白字符组成。
        /// <summary>
        /// 指示指定的字符串是 null、空还是仅由空白字符组成。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns>如果 value 参数为 null 或 System.String.Empty，或者如果 value 仅由空白字符组成，则为 true</returns>
        public static bool IsNullOrWhiteSpace(this object s)
        {
            try
            {
                return string.IsNullOrWhiteSpace(Convert.ToString(s));
            }
            catch (Exception)
            {
                return false;
            }
        }
        #endregion
        #region 指示指定的字符串不是 null 或不是 System.String.Empty 字符串。
        /// <summary>
        /// 指示指定的字符串不是 null 或不是 System.String.Empty 字符串。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns></returns>
        public static bool IsNotNullOrEmpty(this string s)
        {
            return !string.IsNullOrEmpty(s);
        }
        #endregion
        public static bool EndWith(this string s, string t)
        {
            return s.EndsWith(t, true, CultureInfo.CurrentCulture);
        }
        public static bool StartWith(this string s, string t)
        {
            return s.StartsWith(t, true, CultureInfo.CurrentCulture);
        }
        public static bool UrlIsExist(this string url)
        {
            //try
            {
                var uri = new Uri(url);
                return UriIsExist(uri);
            }
            //catch
            //{
            //    return false;
            //}
        }
        public static bool UriIsExist(this Uri uri)
        {
            var isExist = false;
            var req = WebRequest.Create(uri) as HttpWebRequest;
            try
            {
                req.Method = "HEAD";
                var res = req.GetResponse() as HttpWebResponse;
                if (res.StatusCode == HttpStatusCode.OK) isExist = true;
            }
            catch (WebException error)
            {
                try
                {
                    isExist = (((HttpWebResponse)error.Response).StatusCode != HttpStatusCode.NotFound);
                }
                catch
                {
                    isExist = (error.Status == WebExceptionStatus.Success);
                }
            }
            return isExist;
        }
        public static bool ToBoolean(this object obj)
        {
            try
            {
                return Convert.ToBoolean(obj);
            }
            catch
            {
                return false;
            }
        }
        public static bool IsNumberic(this object expression)
        {
            double retnum;
            return Double.TryParse(Convert.ToString(expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retnum);
        }
        public static bool IsInt32Regex(this object obj)
        {
            return !obj.IsNullOrWhiteSpace() && new Regex(@"^\d+$").IsMatch((string)obj);
        }
        public static bool IsInt32(this object expression)
        {
            int retnum;
            return int.TryParse(Convert.ToString(expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retnum);
        }
        #region 指示指定的字符串不是 0。
        /// <summary>
        /// 指示指定的字符串不是 0。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns></returns>
        public static bool IsNotZero(this int s)
        {
            return s != 0;
        }
        #endregion
        #region 指示指定的字符串是 0。
        /// <summary>
        /// 指示指定的字符串不是 0。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns></returns>
        public static bool IsZero(this int s)
        {
            return s == 0;
        }
        #endregion
        #region 指示指定的字符串是 null、空还是仅由空白字符组成。
        /// <summary>
        /// 指示指定的字符串是 null、空还是仅由空白字符组成。
        /// </summary>
        /// <param name="s">要测试的字符串</param>
        /// <returns>如果 value 参数为 null 或 System.String.Empty，或者如果 value 仅由空白字符组成，则为 false</returns>
        public static bool IsNotNullOrWhiteSpace(this string s)
        {
            return !string.IsNullOrWhiteSpace(s);
        }
        #endregion
        #region  将指定字符串中的一个或多个格式项替换为指定对象的字符串表示形式。
        /// <summary>
        /// 将指定字符串中的一个或多个格式项替换为指定对象的字符串表示形式。
        /// </summary>
        /// <param name="format">字符串</param>
        /// <param name="args">要设置的格式对象</param>
        /// <returns></returns>
        public static string FormatWith(this string format, params object[] args)
        {
            return string.Format(format, args);
        }
        #endregion

        public static string UrlDecode(this string s)
        {
            return !string.IsNullOrWhiteSpace(s) ? HttpUtility.UrlDecode(s) : null;
        }

        public static string UrlEncode(this string s)
        {
            return !string.IsNullOrWhiteSpace(s) ? HttpUtility.UrlEncode(s) : null;
        }

        public static string ToNull(this string s)
        {
            return !s.IsNullOrWhiteSpace() ? s.Trim() : null;
        }
        #region 将指定对象转换为 DateTime
        public static DateTime? ToDateTime(this object s, string format = null)
        {
            try
            {
                return format != null ? Convert.ToDateTime(s) : Convert.ToDateTime(Convert.ToDateTime(s).ToString(format ?? "yyyy-MM-dd hh:mm:ss"));
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion
        #region 将指定对象转换为 Double
        public static Double? ToDouble(this object s)
        {
            try
            {
                return Double.Parse(s.ToString());
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion
        #region 将指定字符串转换为 int
        public static int? ToInt(this object s)
        {
            try
            {
                return Convert.ToInt32(s);
            }
            catch (Exception)
            {
                return null; // 无参数，出错时，则返回 null 值。
            }
        }
        /// <summary>
        /// 将指定字符串转换为 int
        /// </summary>
        /// <param name="s"></param>
        /// <param name="i"></param>
        /// <returns>int</returns>
        public static int ToInt(this object s, int i)
        {
            try
            {
                return Convert.ToInt32(s);
            }
            catch (Exception)
            {
                return i; // 出错则返回指定的固定值 i
            }
        }
        #endregion
        public static Int64 ToInt64<T>(this T t, int i)
        {
            try
            {
                return Int64.Parse(t.ToString());
            }
            catch (Exception)
            {
                return i;
            }
        }
        public static IList<T> SplitToList<T>(this object s, char t = ',')
        {
            if (s == null || s.ToString() == "" || !s.ToString().IsNotNullOrWhiteSpace()) return new List<T>();
            return s.ToString().Split(t).ToList() as IList<T>;
        }
        #region 首字母转换为小写
        /// <summary>
        /// 首字母转换为小写
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToCamel(this string s)
        {
            if (s.IsNullOrEmpty())
            {
                return s;
            }
            return s[0].ToString(CultureInfo.InvariantCulture).ToLower() + s.Substring(1);
        }
        #endregion
        #region 首字母转换为大写
        /// <summary>
        /// 首字母转换为大写
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToPascal(this string s)
        {
            if (s.IsNullOrEmpty())
            {
                return s;
            }
            return s[0].ToString(CultureInfo.InvariantCulture).ToUpper() + s.Substring(1);
        }
        #endregion
        #region 比较两个指定的 System.String 对象（其中忽略或考虑其大小写）
        /// <summary>
        /// 比较两个指定的 System.String 对象（其中忽略或考虑其大小写）
        /// </summary>
        /// <param name="strA">要比较的第一个字符串</param>
        /// <param name="strB">要比较的第二个字符串</param>
        /// <param name="ignoreCase">要在比较过程中忽略大小写，则为 true；否则为 false。</param>
        /// <returns></returns>
        public static bool Compare(this string strA, string strB, bool ignoreCase = true)
        {
            return string.Compare(strA, strB, ignoreCase) == 0;
        }
        #endregion
        public static T EnumParse<T>(this string str)
        {
            return (T)Enum.Parse(typeof(T), str, true);
        }
        public static object Replace(this object obj, string str)
        {
            return obj != null ? obj.ToString().Replace(str) : null;
        }
        public static object ToHtml(this object obj)
        {
            return obj != null ? obj.ToString().Replace("&lt;", "<").Replace("&gt;", ">") : null;
        }
        /// 截取文本，区分中英文字符，中文算两个长度，英文算一个长度
        public static object Left(this object str, int length = 120, string split = "…")
        {
            return str != null ? str.ToString().Left(length, split) : null;
        }
        /// 截取文本，区分中英文字符，中文算两个长度，英文算一个长度
        public static string Left(this string str, int length = 120, string split = "…")
        {
            var temp = str;
            temp = Regex.Replace(temp, @"<.+?>", "", RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
            temp = Regex.Replace(temp, @"(&nbsp;|\r|\n| |　|	)+", "　", RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
            temp = temp.Replace(@"　+", "　");
            var j = 0;
            var k = 0;
            for (var i = 0; i < temp.Length; i++)
            {
                if (Regex.IsMatch(temp.Substring(i, 1), @"[\u4e00-\u9fa5]+"))
                    j += 2;
                else
                    j += 1;
                if (j <= length) k += 1;
                if (j > length) return temp.Substring(0, k) + split;
            }
            return temp;
        }
        public static string ReplaceDot(this string str)
        {
            const string ptr = @"(?<dot>['""])(?<Content>[^'""]*)\k<dot>";
            var mcs = Regex.Matches(str, ptr, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Multiline);
            foreach (Match mc in mcs)
            {
                switch (mc.Groups["dot"].Value)
                {
                    case "'":
                        str = str.Remove(mc.Index, mc.Value.Length);
                        str = str.Insert(mc.Index, "‘" + mc.Groups["Content"] + "’");
                        break;
                    case "\"":
                        str = str.Remove(mc.Index, mc.Value.Length);
                        str = str.Insert(mc.Index, "“" + mc.Groups["Content"] + "”");
                        break;
                }
            }
            str = str.Replace(" ", "　").Replace("&nbsp;", "　").Replace("'", "’").Replace("\"", "”");
            return str;
        }
        public static string ObjectToJson(this object instance)
        {
            return JsonConvert.SerializeObject(instance);
        }
        public static string ObjectsToJson<T>(this T instance)
        {
            return JsonConvert.SerializeObject(instance);
        }
        public static T JsonToObject<T>(this object instance)
        {
            return (T)JsonConvert.DeserializeObject(instance.ToString());
        }
        public static List<T> JsonToObjects<T>(this object instance)
        {
            return JsonConvert.DeserializeObject<List<T>>(instance.ToString());
        }
        public static string JsonSerializer<T>(this T t)
        {
            var ser = new DataContractJsonSerializer(typeof(T));
            var ms = new MemoryStream();
            ser.WriteObject(ms, t);
            var json = Encoding.UTF8.GetString(ms.ToArray());
            ms.Close();
            return json;
        }
        #endregion
    }
}
